import socket
import struct
import logging
import os

import chardet

from ST1.settings import MEDIA_ROOT, File_SCR, ADJUST_LOG
import threading
import datetime
import ctypes
import codecs

lock = threading.Lock()

# HOST = "127.0.0.1"
# PORT = 10501
# recv_buffer = 8192

POLYNOMIAL = 0x1021
INITIAL_REMAINDER = 0xFFFF
FINAL_XOR_VALUE = 0x0000
WIDTH = 16
TOPBIT = (1 << (WIDTH - 1))
crcTable = {}

message_info = ["adjust_anca", "translate_ready", "file_info"]


def crcInit():
    SHIFT = WIDTH - 8
    for step in range(0, 256):
        remainder = step << SHIFT
        for bit in range(8, 0, -1):
            if remainder & TOPBIT:
                remainder = ((remainder << 1) & 0xFFFF) ^ 0x1021
            else:
                remainder = remainder << 1
        crcTable[step] = remainder


def crcFast(message, nBytes):
    """
    crc文件校驗
    :param message: 文件內容
    :param nBytes: 文件大小
    :return:
    """
    crcInit()
    remainder = 0xFFFF
    # data = 0
    byte = 0
    while byte < nBytes:
        # print("ord(message[byte]):",ord(message[byte]),message[byte])
        data = ord(message[byte]) ^ (remainder >> (WIDTH - 8))
        remainder = crcTable[data] ^ ((remainder << 8) & 0xFFFF)
        byte = byte + 1

    return hex(remainder)[2:]


def get_file_info(filepath):
    # open(file)
    pass


def adjust_so(d_code, me_num, g_size, file_path):
    """
    調用c++文件生成.scr腳本
    :param d_code: 尺寸代碼
    :param me_num: 測量值
    :param g_size: 標準值
    :param file_path: scr文件路徑
    :return: 狀態
    """
    para = d_code + "|" + g_size + "|" + me_num + "|" + file_path

    so = ctypes.cdll.LoadLibrary
    lib = so("/mysite/stwebservice/smart_cutter/ToolMillAutoOffset.so")
    # lib = so(so_file_path)

    a = lib.creatNewScr(para, len(para))

    return a


class TranslateFile(object):
    """
       1. 客戶端連接配置
       2.發送調機準備消息，接收文件信息和crc16校驗碼
       3.接收文件信息和校驗碼后發送文件文件接收準備消息
       4.接收文件并存儲
       5.調用.so文件，將.scr文件路徑和檢測值等參數傳給.so文件生成一個新的.scr文件
       6.將生成的新.scr文件信息傳輸給幾台
       7.收到準備消息后將生成的.scr文件傳遞給幾台
       8.接收幾台驗證消息判斷文件是否傳輸成功


       :param host:連接的主機名
       port:端口
       recv_buffer:單次傳輸的文件大小
       me_num:砂輪的測量值
       g_size:砂輪的標準值
       d_code：尺寸代碼
    """

    def __init__(self, host=None, port=None, recv_buffer=None, me_num=None, g_size=None, d_code=None):
        # threading.Thread.__init__(self)
        self.host = host
        self.port = port
        self.recv_buffer = recv_buffer
        self.me_num = me_num
        self.g_size = g_size
        self.d_code = d_code
        log_file_path = os.path.join(MEDIA_ROOT, ADJUST_LOG)
        log_file_name = "%s.%s" % ("adjust", "log")
        if not os.path.exists(log_file_path):
            if lock.acquire():
                try:
                    os.makedirs(log_file_path)
                finally:
                    lock.release()
        log_file_path = os.path.join(log_file_path, log_file_name)

        logging.basicConfig(filename=log_file_path,
                            format='[%(asctime)s-%(filename)s-%(levelname)s:%(message)s]', level=logging.INFO,
                            filemode='a', datefmt='%Y-%m-%d %I:%M:%S %p')

    def adjust(self):
        global sock
        global message

        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        logging.info("start connect into server....")
        try:
            sock.connect((self.host, self.port))
            logging.info("connected into server %s...." % self.host)
            # print("連接成功")
        except Exception as e:
            logging.info(str(e))

        sock.send(message_info[0].encode('UTF-8'))
        adjust_reply = sock.recv(50)
        adjust_reply = adjust_reply.decode()
        # print("服務器文件信息：", adjust_reply)
        logging.info("recvied message successed")
        logging.info(adjust_reply)

        # print("adjust_reply",adjust_reply)
        if adjust_reply:
            message_list = adjust_reply.split(" ")
            file_size = int(message_list[0][9:])
            # print("file_size:", file_size)
            crc_code = int(message_list[1])

            sock.send(message_info[1].encode("UTF-8"))
            file_path = os.path.join(MEDIA_ROOT, File_SCR)
            file_path = os.path.join("", file_path)
            # print("file_path:",file_path)
            if not os.path.exists(file_path):
                if lock.acquire():
                    try:
                        os.makedirs(file_path)
                    finally:
                        lock.release()
            # file_name = "%s.%s" % ("new", "scr")
            logging.info("filepath create successed")
            absolute_path = os.path.join(file_path, 'new.scr')
            # print("absolute_path",absolute_path)
            new_file = open(absolute_path, 'wb')
            # print('file open successed')
            recved_size = 0
            logging.info("start receive %s .scr..." % self.host)
            if lock.acquire():  # 獲得鎖，避免文件操作異常
                try:
                    while True:
                        file_reply = sock.recv(self.recv_buffer)
                        new_file.write(file_reply)
                        recved_size += len(file_reply)
                        if file_size == recved_size:
                            break
                    new_file.close()
                    logging.info("receive %s .scr completed..." % self.host)

                    # print('file successed')
                    # print("absolute_path", absolute_path)
                    try:
                        newfile = open(absolute_path, 'rb')
                        file_context = newfile.read()
                        file_context_aa = file_context.decode("ISO-8859-1")
                        local_crc_code = crcFast(file_context_aa, len(file_context_aa))
                        local_crc_code = int(local_crc_code, 16)
                        logging.info("adjust file successed")
                    except Exception as e:
                        logging.error(str(e))
                    finally:
                        newfile.close()
                    logging.info("file debug successed")

                    if local_crc_code != crc_code: raise Exception("文件校驗碼不匹配，文件傳輸失敗！")
                    # print("校驗成功")
                    logging.info("%s .scr debug successed，start calling the .so file" % self.host)
                    status_code = adjust_so(self.d_code, self.me_num, self.g_size, absolute_path)
                    # print("status:", status_code)
                    if status_code:
                        logging.info("file call succeeded")
                    else:
                        raise Exception(".so file adjust fail！！！")

                    logging.info("Successfully generate a new .scr file and start transferring the file...")

                    test_file_path = os.path.join(file_path, "test.scr")  # .so文件生成的.scr文件
                    # test_scr_size = os.path.getsize("/mysite/fileData2/ST/scr/test.scr")
                    # print("test_file_path",test_file_path)
                    test_scr_size = os.path.getsize(test_file_path)  # 開始獲取新生成的.scr文件信息
                    # testfile = open("/mysite/fileData2/ST/scr/test.scr")

                    testfile = open(test_file_path,'rb')
                    test_file_context = testfile.read()
                    test_file_context = test_file_context.decode("ISO-8859-1")
                    test_local_crc_code = crcFast(test_file_context, len(test_file_context))
                    test_local_crc_code = int(test_local_crc_code, 16)
                    file_info = message_info[2] + str(test_scr_size) + ' ' + str(test_local_crc_code)
                    testfile.close()
                    # file_info = message_info[2] + str(local_file_size) + ' ' + str(local_crc_code)
                    # print("發送給服務器文件信息：", file_info)
                    sock.send(file_info.encode('UTF-8'))  # 將.so文件生成的.scr文件信息發送給幾台

                    ready_info = sock.recv(50)  # 接收到ready狀態后開始發送文件
                    if ready_info.decode() == 'translate_ready':
                        # translate_file = open("/mysite/fileData2/ST/scr/test.scr", 'rb')  # 此文件要修改為.so文件生成的.scr文件
                        translate_file = open(test_file_path, 'rb')  # 此文件要修改為.so文件生成的.scr文件
                        # translate_file = open(absolute_path, 'rb')  # 此文件要修改為.so文件生成的.scr文件
                        while True:
                            file_data = translate_file.read(self.recv_buffer)
                            sock.send(file_data)
                            if not file_data:
                                break
                        translate_file.close()
                    # print("testfile translate successed")
                    # 接收對方返回接收狀態
                    file_status = sock.recv(50)
                    logging.info("failed recvied successed")
                    adjust_status = sock.recv(50)
                    if file_status.decode() == 'receive_finish' and adjust_status.decode() == 'adjust_finish':

                        logging.warning("%s debug successed！！！" % self.host)
                        return "adjust successed"
                    else:
                        raise Exception("%s adjust failed！！！" % self.host)
                except Exception as e:
                    logging.error(str(e))  # 將錯誤信息打印到logging文件
                finally:
                    lock.release()  # 不管文件是否異常都要釋放鎖


def format_time(start, end):
    """
    對時間格式化
    """
    from datetime import datetime

    start = datetime.strptime(start, "%Y-%m-%d %H:%M:%S")
    end = datetime.strptime(end, "%Y-%m-%d %H:%M:%S")
    return start, end


def not_empty(s):
    """
    去除list中的空字符
    """
    return s and s.strip()



